from protolib import pad_or_truncate
from protolib.gui_utils.pyqt5_utils.create_checkerboard_pixmap import createCheckerboardPixmap

from PyQt5.QtWidgets import QWidget
from PyQt5.QtGui import QPainter, QColor, QPixmap

class PixelCanvas(QWidget):
    def __init__(self, parent, width, height, pixel_size, click_callback, drag_callback, mouse_release_callback):
        super().__init__(parent)

        self.canvasWidth = width
        self.canvasHeight = height
        self.pixel_size = pixel_size
        self.click_callback = click_callback
        self.drag_callback = drag_callback
        self.mouse_release_callback = mouse_release_callback
        self.last_changed_pixel = 0, 0
        self.last_mouse_click_point = 0, 0
        self.last_mouse_release_point = 0, 0
        self.regenerate_pixmap()
        self.clear()

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.drawPixmap(0, 0, self.background)
        painter.drawPixmap(0, 0, self.pixmap)

    def drawPixel(self, x, y, color) -> bool:
        if x < self.canvasWidth and y < self.canvasHeight and x >= 0 and y >= 0:
            self.last_changed_pixel = x, y
            self.pixel_colors[x][y] = QColor(color).getRgb()
            painter = QPainter(self.pixmap)
            painter.fillRect(x * self.pixel_size, y * self.pixel_size, self.pixel_size, self.pixel_size, color)
            self.update()
            return True
        return False

    def mousePressEvent(self, event):
        x = event.x() // self.pixel_size
        y = event.y() // self.pixel_size
        self.last_mouse_click_point = x, y
        self.click_callback(event, x, y)

    def mouseMoveEvent(self, event):
        x = event.x() // self.pixel_size
        y = event.y() // self.pixel_size
        self.drag_callback(event, x, y)
        event.accept()

    def mouseReleaseEvent(self, event):
        x = event.x() // self.pixel_size
        y = event.y() // self.pixel_size
        self.last_mouse_release_point = x, y
        self.mouse_release_callback(event, x, y)

    def clear(self):
        self.pixel_colors = [[None for _ in range(self.canvasHeight)] for _ in range(self.canvasWidth)]
        self.refreshCanvas()

    def updateSize(self):
        self.regenerate_pixmap()
        self.pixel_colors = pad_or_truncate(self.pixel_colors, self.canvasWidth)
        for column, _ in enumerate(self.pixel_colors):
            if self.pixel_colors[column] == None:
                self.pixel_colors[column] = [None for _ in range(self.canvasHeight)]
        self.clear()

    def erasePixel(self, x, y):
        if x < self.canvasWidth and y < self.canvasHeight and x >= 0 and y >= 0:
            self.last_changed_pixel = x, y
            self.pixel_colors[x][y] = None
            painter = QPainter(self.pixmap)
            painter.setOpacity(0.0)
            painter.setCompositionMode(QPainter.CompositionMode.CompositionMode_Source)
            painter.fillRect(x * self.pixel_size, y * self.pixel_size, self.pixel_size, self.pixel_size, QColor(0, 0, 0, 0))
            self.update()

    def refreshCanvas(self):
        self.regenerate_pixmap()
        for x, column in enumerate(self.pixel_colors):
            for y, pixel in enumerate(column):
                if pixel is None:
                    self.erasePixel(x, y)
                    continue
                self.drawPixel(x, y, QColor(*pixel))
        self.update()

    def regenerate_pixmap(self):
        self.background = createCheckerboardPixmap(self.canvasWidth * self.pixel_size, self.canvasHeight * self.pixel_size)
        self.pixmap = QPixmap(self.canvasWidth * self.pixel_size, self.canvasHeight * self.pixel_size)
        self.pixmap.fill(QColor(0, 0, 0, 0))
